/**
 * TinyMCE version 7.7.1 (2025-03-05)
 */

(function() {
  "use strict";

  var global$4 = tinymce.util.Tools.resolve("tinymce.PluginManager");

  const getPrototypeOf = Object.getPrototypeOf;
  const hasProto = (v, constructor, predicate) => {
    var _a;
    if (predicate(v, constructor.prototype)) {
      return true;
    } else {
      return ((_a = v.constructor) === null || _a === void 0 ? void 0 : _a.name) === constructor.name;
    }
  };
  const typeOf = x => {
    const t = typeof x;
    if (x === null) {
      return "null";
    } else if (t === "object" && Array.isArray(x)) {
      return "array";
    } else if (t === "object" && hasProto(x, String, (o, proto) => proto.isPrototypeOf(o))) {
      return "string";
    } else {
      return t;
    }
  };
  const isType = type => value => typeOf(value) === type;
  const isSimpleType = type => value => typeof value === type;
  const eq = t => a => t === a;
  const is = (value, constructor) => isObject(value) && hasProto(value, constructor, (o, proto) => getPrototypeOf(o) === proto);
  const isString = isType("string");
  const isObject = isType("object");
  const isPlainObject = value => is(value, Object);
  const isArray = isType("array");
  const isNull = eq(null);
  const isBoolean = isSimpleType("boolean");
  const isNullable = a => a === null || a === undefined;
  const isNonNullable = a => !isNullable(a);
  const isFunction = isSimpleType("function");
  const isNumber = isSimpleType("number");
  const isArrayOf = (value, pred) => {
    if (isArray(value)) {
      for (let i = 0, len = value.length; i < len; ++i) {
        if (!pred(value[i])) {
          return false;
        }
      }
      return true;
    }
    return false;
  };

  const noop = () => {
  };

  class Optional {
    constructor(tag, value) {
      this.tag = tag;
      this.value = value;
    }

    static some(value) {
      return new Optional(true, value);
    }

    static none() {
      return Optional.singletonNone;
    }

    static from(value) {
      return isNonNullable(value) ? Optional.some(value) : Optional.none();
    }

    fold(onNone, onSome) {
      if (this.tag) {
        return onSome(this.value);
      } else {
        return onNone();
      }
    }

    isSome() {
      return this.tag;
    }

    isNone() {
      return !this.tag;
    }

    map(mapper) {
      if (this.tag) {
        return Optional.some(mapper(this.value));
      } else {
        return Optional.none();
      }
    }

    bind(binder) {
      if (this.tag) {
        return binder(this.value);
      } else {
        return Optional.none();
      }
    }

    exists(predicate) {
      return this.tag && predicate(this.value);
    }

    forall(predicate) {
      return !this.tag || predicate(this.value);
    }

    filter(predicate) {
      if (!this.tag || predicate(this.value)) {
        return this;
      } else {
        return Optional.none();
      }
    }

    getOr(replacement) {
      return this.tag ? this.value : replacement;
    }

    or(replacement) {
      return this.tag ? this : replacement;
    }

    getOrThunk(thunk) {
      return this.tag ? this.value : thunk();
    }

    orThunk(thunk) {
      return this.tag ? this : thunk();
    }

    getOrDie(message) {
      if (!this.tag) {
        throw new Error(message !== null && message !== void 0 ? message : "Called getOrDie on None");
      } else {
        return this.value;
      }
    }

    getOrNull() {
      return this.tag ? this.value : null;
    }

    getOrUndefined() {
      return this.value;
    }

    each(worker) {
      if (this.tag) {
        worker(this.value);
      }
    }

    toArray() {
      return this.tag ? [this.value] : [];
    }

    toString() {
      return this.tag ? `some(${this.value})` : "none()";
    }
  }

  Optional.singletonNone = new Optional(false);

  const keys = Object.keys;
  const hasOwnProperty = Object.hasOwnProperty;
  const each = (obj, f) => {
    const props = keys(obj);
    for (let k = 0, len = props.length; k < len; k++) {
      const i = props[k];
      const x = obj[i];
      f(x, i);
    }
  };
  const objAcc = r => (x, i) => {
    r[i] = x;
  };
  const internalFilter = (obj, pred, onTrue, onFalse) => {
    each(obj, (x, i) => {
      (pred(x, i) ? onTrue : onFalse)(x, i);
    });
  };
  const filter = (obj, pred) => {
    const t = {};
    internalFilter(obj, pred, objAcc(t), noop);
    return t;
  };
  const has = (obj, key) => hasOwnProperty.call(obj, key);
  const hasNonNullableKey = (obj, key) => has(obj, key) && obj[key] !== undefined && obj[key] !== null;

  const nativePush = Array.prototype.push;
  const flatten = xs => {
    const r = [];
    for (let i = 0, len = xs.length; i < len; ++i) {
      if (!isArray(xs[i])) {
        throw new Error("Arr.flatten item " + i + " was not an array, input: " + xs);
      }
      nativePush.apply(r, xs[i]);
    }
    return r;
  };
  const get = (xs, i) => i >= 0 && i < xs.length ? Optional.some(xs[i]) : Optional.none();
  const head = xs => get(xs, 0);
  const findMap = (arr, f) => {
    for (let i = 0; i < arr.length; i++) {
      const r = f(arr[i], i);
      if (r.isSome()) {
        return r;
      }
    }
    return Optional.none();
  };

  typeof window !== "undefined" ? window : Function("return this;")();

  const rawSet = (dom, key, value) => {
    if (isString(value) || isBoolean(value) || isNumber(value)) {
      dom.setAttribute(key, value + "");
    } else {
      console.error("Invalid call to Attribute.set. Key ", key, ":: Value ", value, ":: Element ", dom);
      throw new Error("Attribute value was not simple");
    }
  };
  const set = (element, key, value) => {
    rawSet(element.dom, key, value);
  };
  const remove = (element, key) => {
    element.dom.removeAttribute(key);
  };

  const fromHtml = (html, scope) => {
    const doc = scope || document;
    const div = doc.createElement("div");
    div.innerHTML = html;
    if (!div.hasChildNodes() || div.childNodes.length > 1) {
      const message = "HTML does not have a single root node";
      console.error(message, html);
      throw new Error(message);
    }
    return fromDom(div.childNodes[0]);
  };
  const fromTag = (tag, scope) => {
    const doc = scope || document;
    const node = doc.createElement(tag);
    return fromDom(node);
  };
  const fromText = (text, scope) => {
    const doc = scope || document;
    const node = doc.createTextNode(text);
    return fromDom(node);
  };
  const fromDom = node => {
    if (node === null || node === undefined) {
      throw new Error("Node cannot be null or undefined");
    }
    return { dom: node };
  };
  const fromPoint = (docElm, x, y) => Optional.from(docElm.dom.elementFromPoint(x, y)).map(fromDom);
  const SugarElement = {
    fromHtml,
    fromTag,
    fromText,
    fromDom,
    fromPoint
  };

  var global$3 = tinymce.util.Tools.resolve("tinymce.dom.DOMUtils");

  var global$2 = tinymce.util.Tools.resolve("tinymce.util.URI");

  const isNotEmpty = s => s.length > 0;

  const option = name => editor => editor.options.get(name);
  const register$2 = editor => {
    const registerOption = editor.options.register;
    registerOption("image_dimensions", {
      processor: "boolean",
      default: true
    });
    registerOption("image_advtab", {
      processor: "boolean",
      default: false
    });
    registerOption("image_uploadtab", {
      processor: "boolean",
      default: true
    });
    registerOption("image_prepend_url", {
      processor: "string",
      default: ""
    });
    registerOption("image_class_list", { processor: "object[]" });
    registerOption("image_description", {
      processor: "boolean",
      default: true
    });
    registerOption("image_title", {
      processor: "boolean",
      default: false
    });
    registerOption("image_caption", {
      processor: "boolean",
      default: false
    });
    registerOption("image_list", {
      processor: value => {
        const valid = value === false || isString(value) || isArrayOf(value, isObject) || isFunction(value);
        return valid ? {
          value,
          valid
        } : {
          valid: false,
          message: "Must be false, a string, an array or a function."
        };
      },
      default: false
    });
  };
  const hasDimensions = option("image_dimensions");
  const hasAdvTab = option("image_advtab");
  const hasUploadTab = option("image_uploadtab");
  const getPrependUrl = option("image_prepend_url");
  const getClassList = option("image_class_list");
  const hasDescription = option("image_description");
  const hasImageTitle = option("image_title");
  const hasImageCaption = option("image_caption");
  const getImageList = option("image_list");
  const showAccessibilityOptions = option("a11y_advanced_options");
  const isAutomaticUploadsEnabled = option("automatic_uploads");
  const hasUploadUrl = editor => isNotEmpty(editor.options.get("images_upload_url"));
  const hasUploadHandler = editor => isNonNullable(editor.options.get("images_upload_handler"));

  const parseIntAndGetMax = (val1, val2) => Math.max(parseInt(val1, 10), parseInt(val2, 10));
  const getImageSize = url => new Promise(callback => {
    const img = document.createElement("img");
    const done = dimensions => {
      if (img.parentNode) {
        img.parentNode.removeChild(img);
      }
      callback(dimensions);
    };
    img.addEventListener("load", () => {
      const width = parseIntAndGetMax(img.width, img.clientWidth);
      const height = parseIntAndGetMax(img.height, img.clientHeight);
      const dimensions = {
        width,
        height
      };
      done(Promise.resolve(dimensions));
    });
    img.addEventListener("error", () => {
      done(Promise.reject(`Failed to get image dimensions for: ${url}`));
    });
    const style = img.style;
    style.visibility = "hidden";
    style.position = "fixed";
    style.bottom = style.left = "0px";
    style.width = style.height = "auto";
    document.body.appendChild(img);
    img.src = url;
  });
  const removePixelSuffix = value => {
    if (value) {
      value = value.replace(/px$/, "");
    }
    return value;
  };
  const addPixelSuffix = value => {
    if (value.length > 0 && /^[0-9]+$/.test(value)) {
      value += "px";
    }
    return value;
  };
  const mergeMargins = css => {
    if (css.margin) {
      const splitMargin = String(css.margin).split(" ");
      switch (splitMargin.length) {
        case 1:
          css["margin-top"] = css["margin-top"] || splitMargin[0];
          css["margin-right"] = css["margin-right"] || splitMargin[0];
          css["margin-bottom"] = css["margin-bottom"] || splitMargin[0];
          css["margin-left"] = css["margin-left"] || splitMargin[0];
          break;
        case 2:
          css["margin-top"] = css["margin-top"] || splitMargin[0];
          css["margin-right"] = css["margin-right"] || splitMargin[1];
          css["margin-bottom"] = css["margin-bottom"] || splitMargin[0];
          css["margin-left"] = css["margin-left"] || splitMargin[1];
          break;
        case 3:
          css["margin-top"] = css["margin-top"] || splitMargin[0];
          css["margin-right"] = css["margin-right"] || splitMargin[1];
          css["margin-bottom"] = css["margin-bottom"] || splitMargin[2];
          css["margin-left"] = css["margin-left"] || splitMargin[1];
          break;
        case 4:
          css["margin-top"] = css["margin-top"] || splitMargin[0];
          css["margin-right"] = css["margin-right"] || splitMargin[1];
          css["margin-bottom"] = css["margin-bottom"] || splitMargin[2];
          css["margin-left"] = css["margin-left"] || splitMargin[3];
      }
      delete css.margin;
    }
    return css;
  };
  const createImageList = (editor, callback) => {
    const imageList = getImageList(editor);
    if (isString(imageList)) {
      fetch(imageList).then(res => {
        if (res.ok) {
          res.json().then(callback);
        }
      });
    } else if (isFunction(imageList)) {
      imageList(callback);
    } else {
      callback(imageList);
    }
  };
  const waitLoadImage = (editor, data, imgElm) => {
    const selectImage = () => {
      imgElm.onload = imgElm.onerror = null;
      if (editor.selection) {
        editor.selection.select(imgElm);
        editor.nodeChanged();
      }
    };
    imgElm.onload = () => {
      if (!data.width && !data.height && hasDimensions(editor)) {
        editor.dom.setAttribs(imgElm, {
          width: String(imgElm.clientWidth),
          height: String(imgElm.clientHeight)
        });
      }
      selectImage();
    };
    imgElm.onerror = selectImage;
  };
  const blobToDataUri = blob => new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = () => {
      resolve(reader.result);
    };
    reader.onerror = () => {
      var _a;
      reject((_a = reader.error) === null || _a === void 0 ? void 0 : _a.message);
    };
    reader.readAsDataURL(blob);
  });
  const isPlaceholderImage = imgElm => imgElm.nodeName === "IMG" && (imgElm.hasAttribute("data-mce-object") || imgElm.hasAttribute("data-mce-placeholder"));
  const isSafeImageUrl = (editor, src) => {
    const getOption = editor.options.get;
    return global$2.isDomSafe(src, "img", {
      allow_html_data_urls: getOption("allow_html_data_urls"),
      allow_script_urls: getOption("allow_script_urls"),
      allow_svg_data_urls: getOption("allow_svg_data_urls")
    });
  };

  const DOM = global$3.DOM;
  const getHspace = image => {
    if (image.style.marginLeft && image.style.marginRight && image.style.marginLeft === image.style.marginRight) {
      return removePixelSuffix(image.style.marginLeft);
    } else {
      return "";
    }
  };
  const getVspace = image => {
    if (image.style.marginTop && image.style.marginBottom && image.style.marginTop === image.style.marginBottom) {
      return removePixelSuffix(image.style.marginTop);
    } else {
      return "";
    }
  };
  const getBorder = image => {
    if (image.style.borderWidth) {
      return removePixelSuffix(image.style.borderWidth);
    } else {
      return "";
    }
  };
  const getAttrib = (image, name) => {
    var _a;
    if (image.hasAttribute(name)) {
      return (_a = image.getAttribute(name)) !== null && _a !== void 0 ? _a : "";
    } else {
      return "";
    }
  };
  const hasCaption = image => image.parentNode !== null && image.parentNode.nodeName === "FIGURE";
  const updateAttrib = (image, name, value) => {
    if (value === "" || value === null) {
      image.removeAttribute(name);
    } else {
      image.setAttribute(name, value);
    }
  };
  const wrapInFigure = image => {
    const figureElm = DOM.create("figure", { class: "image" });
    DOM.insertAfter(figureElm, image);
    figureElm.appendChild(image);
    figureElm.appendChild(DOM.create("figcaption", { contentEditable: "true" }, "Caption"));
    figureElm.contentEditable = "false";
  };
  const removeFigure = image => {
    const figureElm = image.parentNode;
    if (isNonNullable(figureElm)) {
      DOM.insertAfter(image, figureElm);
      DOM.remove(figureElm);
    }
  };
  const toggleCaption = image => {
    if (hasCaption(image)) {
      removeFigure(image);
    } else {
      wrapInFigure(image);
    }
  };
  const normalizeStyle = (image, normalizeCss) => {
    const attrValue = image.getAttribute("style");
    const value = normalizeCss(attrValue !== null ? attrValue : "");
    if (value.length > 0) {
      image.setAttribute("style", value);
      image.setAttribute("data-mce-style", value);
    } else {
      image.removeAttribute("style");
    }
  };
  const setSize = (name, normalizeCss) => (image, name, value) => {
    const styles = image.style;
    if (styles[name]) {
      styles[name] = addPixelSuffix(value);
      normalizeStyle(image, normalizeCss);
    } else {
      updateAttrib(image, name, value);
    }
  };
  const getSize = (image, name) => {
    if (image.style[name]) {
      return removePixelSuffix(image.style[name]);
    } else {
      return getAttrib(image, name);
    }
  };
  const setHspace = (image, value) => {
    const pxValue = addPixelSuffix(value);
    image.style.marginLeft = pxValue;
    image.style.marginRight = pxValue;
  };
  const setVspace = (image, value) => {
    const pxValue = addPixelSuffix(value);
    image.style.marginTop = pxValue;
    image.style.marginBottom = pxValue;
  };
  const setBorder = (image, value) => {
    const pxValue = addPixelSuffix(value);
    image.style.borderWidth = pxValue;
  };
  const setBorderStyle = (image, value) => {
    image.style.borderStyle = value;
  };
  const getBorderStyle = image => {
    var _a;
    return (_a = image.style.borderStyle) !== null && _a !== void 0 ? _a : "";
  };
  const isFigure = elm => isNonNullable(elm) && elm.nodeName === "FIGURE";
  const isImage = elm => elm.nodeName === "IMG";
  const getIsDecorative = image => DOM.getAttrib(image, "alt").length === 0 && DOM.getAttrib(image, "role") === "presentation";
  const getAlt = image => {
    if (getIsDecorative(image)) {
      return "";
    } else {
      return getAttrib(image, "alt");
    }
  };
  const defaultData = () => ({
    src: "",
    alt: "",
    title: "",
    width: "",
    height: "",
    class: "",
    style: "",
    caption: false,
    hspace: "",
    vspace: "",
    border: "",
    borderStyle: "",
    isDecorative: false
  });
  const getStyleValue = (normalizeCss, data) => {
    var _a;
    const image = document.createElement("img");
    updateAttrib(image, "style", data.style);
    if (getHspace(image) || data.hspace !== "") {
      setHspace(image, data.hspace);
    }
    if (getVspace(image) || data.vspace !== "") {
      setVspace(image, data.vspace);
    }
    if (getBorder(image) || data.border !== "") {
      setBorder(image, data.border);
    }
    if (getBorderStyle(image) || data.borderStyle !== "") {
      setBorderStyle(image, data.borderStyle);
    }
    return normalizeCss((_a = image.getAttribute("style")) !== null && _a !== void 0 ? _a : "");
  };
  const create = (normalizeCss, data) => {
    const image = document.createElement("img");
    write(normalizeCss, {
      ...data,
      caption: false
    }, image);
    setAlt(image, data.alt, data.isDecorative);
    if (data.caption) {
      const figure = DOM.create("figure", { class: "image" });
      figure.appendChild(image);
      figure.appendChild(DOM.create("figcaption", { contentEditable: "true" }, "Caption"));
      figure.contentEditable = "false";
      return figure;
    } else {
      return image;
    }
  };
  const read = (normalizeCss, image) => ({
    src: getAttrib(image, "src"),
    alt: getAlt(image),
    title: getAttrib(image, "title"),
    width: getSize(image, "width"),
    height: getSize(image, "height"),
    class: getAttrib(image, "class"),
    style: normalizeCss(getAttrib(image, "style")),
    caption: hasCaption(image),
    hspace: getHspace(image),
    vspace: getVspace(image),
    border: getBorder(image),
    borderStyle: getBorderStyle(image),
    isDecorative: getIsDecorative(image)
  });
  const updateProp = (image, oldData, newData, name, set) => {
    if (newData[name] !== oldData[name]) {
      set(image, name, String(newData[name]));
    }
  };
  const setAlt = (image, alt, isDecorative) => {
    if (isDecorative) {
      DOM.setAttrib(image, "role", "presentation");
      const sugarImage = SugarElement.fromDom(image);
      set(sugarImage, "alt", "");
    } else {
      if (isNull(alt)) {
        const sugarImage = SugarElement.fromDom(image);
        remove(sugarImage, "alt");
      } else {
        const sugarImage = SugarElement.fromDom(image);
        set(sugarImage, "alt", alt);
      }
      if (DOM.getAttrib(image, "role") === "presentation") {
        DOM.setAttrib(image, "role", "");
      }
    }
  };
  const updateAlt = (image, oldData, newData) => {
    if (newData.alt !== oldData.alt || newData.isDecorative !== oldData.isDecorative) {
      setAlt(image, newData.alt, newData.isDecorative);
    }
  };
  const normalized = (set, normalizeCss) => (image, name, value) => {
    set(image, value);
    normalizeStyle(image, normalizeCss);
  };
  const write = (normalizeCss, newData, image) => {
    const oldData = read(normalizeCss, image);
    updateProp(image, oldData, newData, "caption", (image, _name, _value) => toggleCaption(image));
    updateProp(image, oldData, newData, "src", updateAttrib);
    updateProp(image, oldData, newData, "title", updateAttrib);
    updateProp(image, oldData, newData, "width", setSize("width", normalizeCss));
    updateProp(image, oldData, newData, "height", setSize("height", normalizeCss));
    updateProp(image, oldData, newData, "class", updateAttrib);
    updateProp(image, oldData, newData, "style", normalized((image, value) => updateAttrib(image, "style", value), normalizeCss));
    updateProp(image, oldData, newData, "hspace", normalized(setHspace, normalizeCss));
    updateProp(image, oldData, newData, "vspace", normalized(setVspace, normalizeCss));
    updateProp(image, oldData, newData, "border", normalized(setBorder, normalizeCss));
    updateProp(image, oldData, newData, "borderStyle", normalized(setBorderStyle, normalizeCss));
    updateAlt(image, oldData, newData);
  };

  const normalizeCss$1 = (editor, cssText) => {
    const css = editor.dom.styles.parse(cssText);
    const mergedCss = mergeMargins(css);
    const compressed = editor.dom.styles.parse(editor.dom.styles.serialize(mergedCss));
    return editor.dom.styles.serialize(compressed);
  };
  const getSelectedImage = editor => {
    const imgElm = editor.selection.getNode();
    const figureElm = editor.dom.getParent(imgElm, "figure.image");
    if (figureElm) {
      return editor.dom.select("img", figureElm)[0];
    }
    if (imgElm && (imgElm.nodeName !== "IMG" || isPlaceholderImage(imgElm))) {
      return null;
    }
    return imgElm;
  };
  const splitTextBlock = (editor, figure) => {
    var _a;
    const dom = editor.dom;
    const textBlockElements = filter(editor.schema.getTextBlockElements(), (_, parentElm) => !editor.schema.isValidChild(parentElm, "figure"));
    const textBlock = dom.getParent(figure.parentNode, node => hasNonNullableKey(textBlockElements, node.nodeName), editor.getBody());
    if (textBlock) {
      return (_a = dom.split(textBlock, figure)) !== null && _a !== void 0 ? _a : figure;
    } else {
      return figure;
    }
  };
  const readImageDataFromSelection = editor => {
    const image = getSelectedImage(editor);
    return image ? read(css => normalizeCss$1(editor, css), image) : defaultData();
  };
  const insertImageAtCaret = (editor, data) => {
    const elm = create(css => normalizeCss$1(editor, css), data);
    editor.dom.setAttrib(elm, "data-mce-id", "__mcenew");
    editor.focus();
    editor.selection.setContent(elm.outerHTML);
    const insertedElm = editor.dom.select("*[data-mce-id=\"__mcenew\"]")[0];
    editor.dom.setAttrib(insertedElm, "data-mce-id", null);
    if (isFigure(insertedElm)) {
      const figure = splitTextBlock(editor, insertedElm);
      editor.selection.select(figure);
    } else {
      editor.selection.select(insertedElm);
    }
  };
  const syncSrcAttr = (editor, image) => {
    editor.dom.setAttrib(image, "src", image.getAttribute("src"));
  };
  const deleteImage = (editor, image) => {
    if (image) {
      const elm = editor.dom.is(image.parentNode, "figure.image") ? image.parentNode : image;
      editor.dom.remove(elm);
      editor.focus();
      editor.nodeChanged();
      if (editor.dom.isEmpty(editor.getBody())) {
        editor.setContent("");
        editor.selection.setCursorLocation();
      }
    }
  };
  const writeImageDataToSelection = (editor, data) => {
    const image = getSelectedImage(editor);
    if (image) {
      write(css => normalizeCss$1(editor, css), data, image);
      syncSrcAttr(editor, image);
      if (isFigure(image.parentNode)) {
        editor.dom.setStyle(image, "float", "");
        const figure = image.parentNode;
        splitTextBlock(editor, figure);
        editor.selection.select(image.parentNode);
      } else {
        editor.selection.select(image);
        waitLoadImage(editor, data, image);
      }
    }
  };
  const sanitizeImageData = (editor, data) => {
    const src = data.src;
    return {
      ...data,
      src: isSafeImageUrl(editor, src) ? src : ""
    };
  };
  const insertOrUpdateImage = (editor, partialData) => {
    const image = getSelectedImage(editor);
    if (image) {
      const selectedImageData = read(css => normalizeCss$1(editor, css), image);
      const data = {
        ...selectedImageData,
        ...partialData
      };
      const sanitizedData = sanitizeImageData(editor, data);
      if (data.src) {
        writeImageDataToSelection(editor, sanitizedData);
      } else {
        deleteImage(editor, image);
      }
    } else if (partialData.src) {
      insertImageAtCaret(editor, {
        ...defaultData(),
        ...partialData
      });
    }
  };

  const deep = (old, nu) => {
    const bothObjects = isPlainObject(old) && isPlainObject(nu);
    return bothObjects ? deepMerge(old, nu) : nu;
  };
  const baseMerge = merger => {
    return (...objects) => {
      if (objects.length === 0) {
        throw new Error(`Can't merge zero objects`);
      }
      const ret = {};
      for (let j = 0; j < objects.length; j++) {
        const curObject = objects[j];
        for (const key in curObject) {
          if (has(curObject, key)) {
            ret[key] = merger(ret[key], curObject[key]);
          }
        }
      }
      return ret;
    };
  };
  const deepMerge = baseMerge(deep);

  var global$1 = tinymce.util.Tools.resolve("tinymce.util.ImageUploader");

  var global = tinymce.util.Tools.resolve("tinymce.util.Tools");

  const getValue = item => isString(item.value) ? item.value : "";
  const getText = item => {
    if (isString(item.text)) {
      return item.text;
    } else if (isString(item.title)) {
      return item.title;
    } else {
      return "";
    }
  };
  const sanitizeList = (list, extractValue) => {
    const out = [];
    global.each(list, item => {
      const text = getText(item);
      if (item.menu !== undefined) {
        const items = sanitizeList(item.menu, extractValue);
        out.push({
          text,
          items
        });
      } else {
        const value = extractValue(item);
        out.push({
          text,
          value
        });
      }
    });
    return out;
  };
  const sanitizer = (extractor = getValue) => list => {
    if (list) {
      return Optional.from(list).map(list => sanitizeList(list, extractor));
    } else {
      return Optional.none();
    }
  };
  const sanitize = list => sanitizer(getValue)(list);
  const isGroup = item => has(item, "items");
  const findEntryDelegate = (list, value) => findMap(list, item => {
    if (isGroup(item)) {
      return findEntryDelegate(item.items, value);
    } else if (item.value === value) {
      return Optional.some(item);
    } else {
      return Optional.none();
    }
  });
  const findEntry = (optList, value) => optList.bind(list => findEntryDelegate(list, value));
  const ListUtils = {
    sanitizer,
    sanitize,
    findEntry
  };

  const makeTab$2 = _info => ({
    title: "Advanced",
    name: "advanced",
    items: [{
      type: "grid",
      columns: 2,
      items: [
        {
          type: "input",
          label: "Vertical space",
          name: "vspace",
          inputMode: "numeric"
        },
        {
          type: "input",
          label: "Horizontal space",
          name: "hspace",
          inputMode: "numeric"
        },
        {
          type: "input",
          label: "Border width",
          name: "border",
          inputMode: "numeric"
        },
        {
          type: "listbox",
          name: "borderstyle",
          label: "Border style",
          items: [
            {
              text: "Select...",
              value: ""
            },
            {
              text: "Solid",
              value: "solid"
            },
            {
              text: "Dotted",
              value: "dotted"
            },
            {
              text: "Dashed",
              value: "dashed"
            },
            {
              text: "Double",
              value: "double"
            },
            {
              text: "Groove",
              value: "groove"
            },
            {
              text: "Ridge",
              value: "ridge"
            },
            {
              text: "Inset",
              value: "inset"
            },
            {
              text: "Outset",
              value: "outset"
            },
            {
              text: "None",
              value: "none"
            },
            {
              text: "Hidden",
              value: "hidden"
            }
          ]
        }
      ]
    }]
  });
  const AdvTab = { makeTab: makeTab$2 };

  const collect = editor => {
    const urlListSanitizer = ListUtils.sanitizer(item => editor.convertURL(item.value || item.url || "", "src"));
    const futureImageList = new Promise(completer => {
      createImageList(editor, imageList => {
        completer(urlListSanitizer(imageList).map(items => flatten([
          [{
            text: "None",
            value: ""
          }],
          items
        ])));
      });
    });
    const classList = ListUtils.sanitize(getClassList(editor));
    const hasAdvTab$1 = hasAdvTab(editor);
    const hasUploadTab$1 = hasUploadTab(editor);
    const hasUploadUrl$1 = hasUploadUrl(editor);
    const hasUploadHandler$1 = hasUploadHandler(editor);
    const image = readImageDataFromSelection(editor);
    const hasDescription$1 = hasDescription(editor);
    const hasImageTitle$1 = hasImageTitle(editor);
    const hasDimensions$1 = hasDimensions(editor);
    const hasImageCaption$1 = hasImageCaption(editor);
    const hasAccessibilityOptions = showAccessibilityOptions(editor);
    const automaticUploads = isAutomaticUploadsEnabled(editor);
    const prependURL = Optional.some(getPrependUrl(editor)).filter(preUrl => isString(preUrl) && preUrl.length > 0);
    return futureImageList.then(imageList => ({
      image,
      imageList,
      classList,
      hasAdvTab: hasAdvTab$1,
      hasUploadTab: hasUploadTab$1,
      hasUploadUrl: hasUploadUrl$1,
      hasUploadHandler: hasUploadHandler$1,
      hasDescription: hasDescription$1,
      hasImageTitle: hasImageTitle$1,
      hasDimensions: hasDimensions$1,
      hasImageCaption: hasImageCaption$1,
      prependURL,
      hasAccessibilityOptions,
      automaticUploads
    }));
  };

  const makeItems = info => {
    const imageUrl = {
      name: "src",
      type: "urlinput",
      filetype: "image",
      label: "Source",
      picker_text: "Browse files"
    };
    const imageList = info.imageList.map(items => ({
      name: "images",
      type: "listbox",
      label: "Image list",
      items
    }));
    const imageDescription = {
      name: "alt",
      type: "input",
      label: "Alternative description",
      enabled: !(info.hasAccessibilityOptions && info.image.isDecorative)
    };
    const imageTitle = {
      name: "title",
      type: "input",
      label: "Image title"
    };
    const imageDimensions = {
      name: "dimensions",
      type: "sizeinput"
    };
    const isDecorative = {
      type: "label",
      label: "Accessibility",
      items: [{
        name: "isDecorative",
        type: "checkbox",
        label: "Image is decorative"
      }]
    };
    const classList = info.classList.map(items => ({
      name: "classes",
      type: "listbox",
      label: "Class",
      items
    }));
    const caption = {
      type: "label",
      label: "Caption",
      items: [{
        type: "checkbox",
        name: "caption",
        label: "Show caption"
      }]
    };
    const getDialogContainerType = useColumns => useColumns ? {
      type: "grid",
      columns: 2
    } : { type: "panel" };
    return flatten([
      [imageUrl],
      imageList.toArray(),
      info.hasAccessibilityOptions && info.hasDescription ? [isDecorative] : [],
      info.hasDescription ? [imageDescription] : [],
      info.hasImageTitle ? [imageTitle] : [],
      info.hasDimensions ? [imageDimensions] : [],
      [{
        ...getDialogContainerType(info.classList.isSome() && info.hasImageCaption),
        items: flatten([
          classList.toArray(),
          info.hasImageCaption ? [caption] : []
        ])
      }]
    ]);
  };
  const makeTab$1 = info => ({
    title: "General",
    name: "general",
    items: makeItems(info)
  });
  const MainTab = {
    makeTab: makeTab$1,
    makeItems
  };

  const makeTab = _info => {
    const items = [{
      type: "dropzone",
      name: "fileinput"
    }];
    return {
      title: "Upload",
      name: "upload",
      items
    };
  };
  const UploadTab = { makeTab };

  const createState = info => ({
    prevImage: ListUtils.findEntry(info.imageList, info.image.src),
    prevAlt: info.image.alt,
    open: true
  });
  const fromImageData = image => ({
    src: {
      value: image.src,
      meta: {}
    },
    images: image.src,
    alt: image.alt,
    title: image.title,
    dimensions: {
      width: image.width,
      height: image.height
    },
    classes: image.class,
    caption: image.caption,
    style: image.style,
    vspace: image.vspace,
    border: image.border,
    hspace: image.hspace,
    borderstyle: image.borderStyle,
    fileinput: [],
    isDecorative: image.isDecorative
  });
  const toImageData = (data, removeEmptyAlt) => ({
    src: data.src.value,
    alt: (data.alt === null || data.alt.length === 0) && removeEmptyAlt ? null : data.alt,
    title: data.title,
    width: data.dimensions.width,
    height: data.dimensions.height,
    class: data.classes,
    style: data.style,
    caption: data.caption,
    hspace: data.hspace,
    vspace: data.vspace,
    border: data.border,
    borderStyle: data.borderstyle,
    isDecorative: data.isDecorative
  });
  const addPrependUrl2 = (info, srcURL) => {
    if (!/^(?:[a-zA-Z]+:)?\/\//.test(srcURL)) {
      return info.prependURL.bind(prependUrl => {
        if (srcURL.substring(0, prependUrl.length) !== prependUrl) {
          return Optional.some(prependUrl + srcURL);
        }
        return Optional.none();
      });
    }
    return Optional.none();
  };
  const addPrependUrl = (info, api) => {
    const data = api.getData();
    addPrependUrl2(info, data.src.value).each(srcURL => {
      api.setData({
        src: {
          value: srcURL,
          meta: data.src.meta
        }
      });
    });
  };
  const formFillFromMeta2 = (info, data, meta) => {
    if (info.hasDescription && isString(meta.alt)) {
      data.alt = meta.alt;
    }
    if (info.hasAccessibilityOptions) {
      data.isDecorative = meta.isDecorative || data.isDecorative || false;
    }
    if (info.hasImageTitle && isString(meta.title)) {
      data.title = meta.title;
    }
    if (info.hasDimensions) {
      if (isString(meta.width)) {
        data.dimensions.width = meta.width;
      }
      if (isString(meta.height)) {
        data.dimensions.height = meta.height;
      }
    }
    if (isString(meta.class)) {
      ListUtils.findEntry(info.classList, meta.class).each(entry => {
        data.classes = entry.value;
      });
    }
    if (info.hasImageCaption) {
      if (isBoolean(meta.caption)) {
        data.caption = meta.caption;
      }
    }
    if (info.hasAdvTab) {
      if (isString(meta.style)) {
        data.style = meta.style;
      }
      if (isString(meta.vspace)) {
        data.vspace = meta.vspace;
      }
      if (isString(meta.border)) {
        data.border = meta.border;
      }
      if (isString(meta.hspace)) {
        data.hspace = meta.hspace;
      }
      if (isString(meta.borderstyle)) {
        data.borderstyle = meta.borderstyle;
      }
    }
  };
  const formFillFromMeta = (info, api) => {
    const data = api.getData();
    const meta = data.src.meta;
    if (meta !== undefined) {
      const newData = deepMerge({}, data);
      formFillFromMeta2(info, newData, meta);
      api.setData(newData);
    }
  };
  const calculateImageSize = (helpers, info, state, api) => {
    const data = api.getData();
    const url = data.src.value;
    const meta = data.src.meta || {};
    if (!meta.width && !meta.height && info.hasDimensions) {
      if (isNotEmpty(url)) {
        helpers.imageSize(url).then(size => {
          if (state.open) {
            api.setData({ dimensions: size });
          }
        }).catch(e => console.error(e));
      } else {
        api.setData({
          dimensions: {
            width: "",
            height: ""
          }
        });
      }
    }
  };
  const updateImagesDropdown = (info, state, api) => {
    const data = api.getData();
    const image = ListUtils.findEntry(info.imageList, data.src.value);
    state.prevImage = image;
    api.setData({ images: image.map(entry => entry.value).getOr("") });
  };
  const changeSrc = (helpers, info, state, api) => {
    addPrependUrl(info, api);
    formFillFromMeta(info, api);
    calculateImageSize(helpers, info, state, api);
    updateImagesDropdown(info, state, api);
  };
  const changeImages = (helpers, info, state, api) => {
    const data = api.getData();
    const image = ListUtils.findEntry(info.imageList, data.images);
    image.each(img => {
      const updateAlt = data.alt === "" || state.prevImage.map(image => image.text === data.alt).getOr(false);
      if (updateAlt) {
        if (img.value === "") {
          api.setData({
            src: img,
            alt: state.prevAlt
          });
        } else {
          api.setData({
            src: img,
            alt: img.text
          });
        }
      } else {
        api.setData({ src: img });
      }
    });
    state.prevImage = image;
    changeSrc(helpers, info, state, api);
  };
  const changeFileInput = (helpers, info, state, api) => {
    const data = api.getData();
    api.block("Uploading image");
    head(data.fileinput).fold(() => {
      api.unblock();
    }, file => {
      const blobUri = URL.createObjectURL(file);
      const finalize = () => {
        api.unblock();
        URL.revokeObjectURL(blobUri);
      };
      const updateSrcAndSwitchTab = url => {
        api.setData({
          src: {
            value: url,
            meta: {}
          }
        });
        api.showTab("general");
        changeSrc(helpers, info, state, api);
        api.focus("src");
      };
      blobToDataUri(file).then(dataUrl => {
        const blobInfo = helpers.createBlobCache(file, blobUri, dataUrl);
        if (info.automaticUploads) {
          helpers.uploadImage(blobInfo).then(result => {
            updateSrcAndSwitchTab(result.url);
            finalize();
          }).catch(err => {
            finalize();
            helpers.alertErr(err, () => {
              api.focus("fileinput");
            });
          });
        } else {
          helpers.addToBlobCache(blobInfo);
          updateSrcAndSwitchTab(blobInfo.blobUri());
          api.unblock();
        }
      });
    });
  };
  const changeHandler = (helpers, info, state) => (api, evt) => {
    if (evt.name === "src") {
      changeSrc(helpers, info, state, api);
    } else if (evt.name === "images") {
      changeImages(helpers, info, state, api);
    } else if (evt.name === "alt") {
      state.prevAlt = api.getData().alt;
    } else if (evt.name === "fileinput") {
      changeFileInput(helpers, info, state, api);
    } else if (evt.name === "isDecorative") {
      api.setEnabled("alt", !api.getData().isDecorative);
    }
  };
  const closeHandler = state => () => {
    state.open = false;
  };
  const makeDialogBody = info => {
    if (info.hasAdvTab || info.hasUploadUrl || info.hasUploadHandler) {
      const tabPanel = {
        type: "tabpanel",
        tabs: flatten([
          [MainTab.makeTab(info)],
          info.hasAdvTab ? [AdvTab.makeTab(info)] : [],
          info.hasUploadTab && (info.hasUploadUrl || info.hasUploadHandler) ? [UploadTab.makeTab(info)] : []
        ])
      };
      return tabPanel;
    } else {
      const panel = {
        type: "panel",
        items: MainTab.makeItems(info)
      };
      return panel;
    }
  };
  const submitHandler = (editor, info, helpers) => api => {
    const data = deepMerge(fromImageData(info.image), api.getData());
    const finalData = {
      ...data,
      style: getStyleValue(helpers.normalizeCss, toImageData(data, false))
    };
    editor.execCommand("mceUpdateImage", false, toImageData(finalData, info.hasAccessibilityOptions));
    editor.editorUpload.uploadImagesAuto();
    api.close();
  };
  const imageSize = editor => url => {
    if (!isSafeImageUrl(editor, url)) {
      return Promise.resolve({
        width: "",
        height: ""
      });
    } else {
      return getImageSize(editor.documentBaseURI.toAbsolute(url)).then(dimensions => ({
        width: String(dimensions.width),
        height: String(dimensions.height)
      }));
    }
  };
  const createBlobCache = editor => (file, blobUri, dataUrl) => {
    var _a;
    return editor.editorUpload.blobCache.create({
      blob: file,
      blobUri,
      name: (_a = file.name) === null || _a === void 0 ? void 0 : _a.replace(/\.[^\.]+$/, ""),
      filename: file.name,
      base64: dataUrl.split(",")[1]
    });
  };
  const addToBlobCache = editor => blobInfo => {
    editor.editorUpload.blobCache.add(blobInfo);
  };
  const alertErr = editor => (message, callback) => {
    editor.windowManager.alert(message, callback);
  };
  const normalizeCss = editor => cssText => normalizeCss$1(editor, cssText);
  const parseStyle = editor => cssText => editor.dom.parseStyle(cssText);
  const serializeStyle = editor => (stylesArg, name) => editor.dom.serializeStyle(stylesArg, name);
  const uploadImage = editor => blobInfo => global$1(editor).upload([blobInfo], false).then(results => {
    var _a;
    if (results.length === 0) {
      return Promise.reject("Failed to upload image");
    } else if (results[0].status === false) {
      return Promise.reject((_a = results[0].error) === null || _a === void 0 ? void 0 : _a.message);
    } else {
      return results[0];
    }
  });
  const Dialog = editor => {
    const helpers = {
      imageSize: imageSize(editor),
      addToBlobCache: addToBlobCache(editor),
      createBlobCache: createBlobCache(editor),
      alertErr: alertErr(editor),
      normalizeCss: normalizeCss(editor),
      parseStyle: parseStyle(editor),
      serializeStyle: serializeStyle(editor),
      uploadImage: uploadImage(editor)
    };
    const open = () => {
      collect(editor).then(info => {
        const state = createState(info);
        return {
          title: "Insert/Edit Image",
          size: "normal",
          body: makeDialogBody(info),
          buttons: [
            {
              type: "cancel",
              name: "cancel",
              text: "Cancel"
            },
            {
              type: "submit",
              name: "save",
              text: "Save",
              primary: true
            }
          ],
          initialData: fromImageData(info.image),
          onSubmit: submitHandler(editor, info, helpers),
          onChange: changeHandler(helpers, info, state),
          onClose: closeHandler(state)
        };
      }).then(editor.windowManager.open);
    };
    return { open };
  };

  const register$1 = editor => {
    editor.addCommand("mceImage", Dialog(editor).open);
    editor.addCommand("mceUpdateImage", (_ui, data) => {
      editor.undoManager.transact(() => insertOrUpdateImage(editor, data));
    });
  };

  const hasImageClass = node => {
    const className = node.attr("class");
    return isNonNullable(className) && /\bimage\b/.test(className);
  };
  const toggleContentEditableState = state => nodes => {
    let i = nodes.length;
    const toggleContentEditable = node => {
      node.attr("contenteditable", state ? "true" : null);
    };
    while (i--) {
      const node = nodes[i];
      if (hasImageClass(node)) {
        node.attr("contenteditable", state ? "false" : null);
        global.each(node.getAll("figcaption"), toggleContentEditable);
      }
    }
  };
  const setup = editor => {
    editor.on("PreInit", () => {
      editor.parser.addNodeFilter("figure", toggleContentEditableState(true));
      editor.serializer.addNodeFilter("figure", toggleContentEditableState(false));
    });
  };

  const onSetupEditable = editor => api => {
    const nodeChanged = () => {
      api.setEnabled(editor.selection.isEditable());
    };
    editor.on("NodeChange", nodeChanged);
    nodeChanged();
    return () => {
      editor.off("NodeChange", nodeChanged);
    };
  };
  const register = editor => {
    editor.ui.registry.addToggleButton("image", {
      icon: "image",
      tooltip: "Insert/edit image",
      onAction: Dialog(editor).open,
      onSetup: buttonApi => {
        buttonApi.setActive(isNonNullable(getSelectedImage(editor)));
        const unbindSelectorChanged = editor.selection.selectorChangedWithUnbind("img:not([data-mce-object]):not([data-mce-placeholder]),figure.image", buttonApi.setActive).unbind;
        const unbindEditable = onSetupEditable(editor)(buttonApi);
        return () => {
          unbindSelectorChanged();
          unbindEditable();
        };
      }
    });
    editor.ui.registry.addMenuItem("image", {
      icon: "image",
      text: "Image...",
      onAction: Dialog(editor).open,
      onSetup: onSetupEditable(editor)
    });
    editor.ui.registry.addContextMenu("image", { update: element => editor.selection.isEditable() && (isFigure(element) || isImage(element) && !isPlaceholderImage(element)) ? ["image"] : [] });
  };

  var Plugin = () => {
    global$4.add("image", editor => {
      register$2(editor);
      setup(editor);
      register(editor);
      register$1(editor);
    });
  };

  Plugin();

})();
